/** ****************************************************************************
@defgroup UltraSonicRanging UltraSonicRanging
@ingroup BSP_External
@brief UltraSonicRanging 驱动
@addtogroup UltraSonicRanging
@{
*******************************************************************************/

#include "ultrasonic_ranging.h"

#define LOGTAG "ULTRA_SONIC_RANGING"

void ultrasonic_ranging_init(driver_ultrasonic_ranging_t* dev, FUNC_GPIO_Switch funcTrigSwitch, FUNC_GPIO_IsInOn funcEchoIsOn, uint32_t pollInterval, uint16_t deltaRatio) {
	if(!dev) { return; }
	dev->distance = 0;
	dev->listen = false;
	dev->pollTaskId = NULL;
	dev->pollInterval = pollInterval;
	dev->deltaRatio = deltaRatio;
	dev->funcTrigSwitch = funcTrigSwitch;
	dev->funcEchoIsOn = funcEchoIsOn;
}

void ultrasonic_ranging_setupCallbacks(driver_ultrasonic_ranging_t* dev, FUNC_onUltrasonicRangingChange onChange, void* cookieChange) {
	if(!dev) { return; }
	dev->onChange = onChange; dev->cookieChange = cookieChange;
}

/// @brief 轮询处理循环
static OSTaskDef(rangingTask) {
	if(!cookieLen || !cookieData) { return; }
	driver_ultrasonic_ranging_t *dev = (driver_ultrasonic_ranging_t*)getPointer(cookieData);
	// 未监听时，直接返回
	if(!dev || !dev->listen) { return; }
	
	// 发一个 10us 的高电平脉冲
	dev->funcTrigSwitch(ON);
	osDelayUs(10);
	dev->funcTrigSwitch(OFF);
}

void ultrasonic_ranging_listen(driver_ultrasonic_ranging_t* dev, bool enable) {
	if(!dev || !dev->funcTrigSwitch || !dev->funcEchoIsOn) { return; }
	
	if(!dev->listen && enable) {
		dev->echoBeginTime = 0;
		dev->distance = 0;
	}

	dev->listen = enable;

	if(!dev->pollTaskId && enable) {
		// 创建轮询任务
		dev->pollTaskId = osTaskRunEvery(dev->pollInterval, OSTASK_REPEAT_FOREVER, rangingTask, sizeof(void*), &dev);
	} else if(dev->pollTaskId && !enable) {
		// 如果之前已经创建了轮询任务，但要停止监听，就必须停止任务
		osTaskDestroy(&dev->pollTaskId);
	}
}

/// 事件回调 DPC 任务
static OSTaskDef(dpcEventCallback) {
	if(!cookieLen || !cookieData) { return; }
	driver_ultrasonic_ranging_t *dev = (driver_ultrasonic_ranging_t*)getPointer(cookieData);
	// 未监听时，直接返回
	if(!dev || !dev->listen || !dev->onChange) { return; }
	// 回调
	dev->onChange(dev, dev->distance, dev->cookieChange);
}

void ultrasonic_ranging_irqHandler(driver_ultrasonic_ranging_t* dev) {
	// 未监听时，直接返回
	if(!dev || !dev->listen) { return; }
	
	// 根据 SONIC_ECHO 引脚电平，判断是否回波开始
	if(dev->funcEchoIsOn()) {
		// 记录回波开始时间点
		dev->echoBeginTime = mcu_get_us();
	} 
	else if(dev->echoBeginTime) {
		// 根据回波持续时间计算距离(cm)
		uint32_t distance = mcu_elapsed_us(dev->echoBeginTime) / 58;
		dev->echoBeginTime = 0;		
		// 计算差值
		uint32_t diff = DIFF(dev->distance, distance);
		diff = (diff*20000)/(dev->distance + distance + 1);
		if(diff > dev->deltaRatio) {
			// 只有当差异大于指定值后才记录，防止渐近变化无法触发
			dev->distance = distance;
			// 一定要在中断外执行回调!
			osTaskRunLater(dpcEventCallback, sizeof(void*), &dev);
		}
	}
	else {
		// 错误的中断状态? 未记录回波开始时间
	}
}


/// @}
